package com.developer.platform.application.query.assembler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.developer.platform.application.query.dto.NoticeListDto;
import com.developer.platform.application.query.dto.ResponseModel;
import com.developer.platform.infrastructure.data.mapper.NoticeSystemMapper;
import com.developer.platform.infrastructure.data.mapper.NoticeUserMapper;
import com.developer.platform.infrastructure.data.po.Notice;
import com.developer.platform.infrastructure.data.po.NoticeSystem;
import com.developer.platform.infrastructure.data.po.NoticeUser;
import com.developer.platform.infrastructure.enums.NoticeUserType;
import com.developer.platform.infrastructure.enums.SystemType;
import com.google.common.collect.Lists;
import com.veeker.core.utils.JsonUtils;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;

/**
 * @author ：qiaoliang
 * @date ：2020-11-10
 */
@Component
public class NoticeAssembler extends BaseAssembler {

    private final NoticeUserMapper noticeUserMapper;
    private final NoticeSystemMapper noticeSystemMapper;

    public NoticeAssembler(
        NoticeUserMapper noticeUserMapper,
        NoticeSystemMapper noticeSystemMapper) {
        this.noticeUserMapper = noticeUserMapper;
        this.noticeSystemMapper = noticeSystemMapper;
    }

    public NoticeListDto toNoticeListDto(Notice notice){
        NoticeListDto noticeListDto = new NoticeListDto();
        BeanUtil.copyProperties(notice, noticeListDto);
        this.userName(noticeListDto);
        return noticeListDto;
    }

    public ResponseModel<NoticeListDto> toNoticeListDtoPage(IPage<Notice> page){
        List<Long> ids = Lists.newArrayList();
        List<Long> groupIds = Lists.newArrayList();
        List<Long> templateIds = Lists.newArrayList();
        List<NoticeListDto> collect = page.getRecords().stream().map(notice -> {
            NoticeListDto noticeListDto = new NoticeListDto();
            BeanUtil.copyProperties(notice, noticeListDto);
            noticeListDto.setContents(JsonUtils.toList(notice.getContents(), String.class));
            noticeListDto.setUrls(JsonUtils.toList(notice.getUrls(), String.class));
            ids.add(notice.getId());
            groupIds.add(notice.getGroupId());
            templateIds.add(notice.getTemplateId());
            return noticeListDto;
        }).collect(Collectors.toList());
        this.data(collect, ids, groupIds, templateIds);
        this.userName(collect);
        return new ResponseModel<>(collect, (int)page.getTotal());
    }


    public void data(List<NoticeListDto> collect, List<Long> ids, List<Long> groupIds, List<Long> templateIds){
        if(CollUtil.isNotEmpty(ids)){
            LambdaQueryWrapper<NoticeUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(NoticeUser::getNoticeId, ids);
            List<NoticeUser> noticeUsers = noticeUserMapper.selectList(queryWrapper);

            Map<Long, String> userNameMap = this
                .userNameMap(noticeUsers.parallelStream().map(NoticeUser::getUserId)
                    .collect(Collectors.toList()));
            Map<Long, List<NoticeUser>> noticeUserMap = noticeUsers.parallelStream()
                .collect(Collectors.groupingBy(NoticeUser::getNoticeId));

            LambdaQueryWrapper<NoticeSystem> systemLambdaQueryWrapper = new LambdaQueryWrapper<>();
            systemLambdaQueryWrapper.in(NoticeSystem::getNoticeId, ids);
            List<NoticeSystem> noticeSystems = noticeSystemMapper.selectList(systemLambdaQueryWrapper);
            Map<Long, String> systemNameMap = this
                .systemNameMap(noticeSystems.parallelStream().map(NoticeSystem::getSystemId)
                    .collect(Collectors.toList()));
            Map<Long, List<NoticeSystem>> systemNameListMap = noticeSystems.parallelStream()
                .collect(Collectors
                    .groupingBy(NoticeSystem::getNoticeId));


            Map<Long, String> groupNameMap = this.groupNameMap(groupIds);
            Map<Long, String> templateNameMap = this.templateNameMap(templateIds);

            collect.forEach(noticeListDto->{
                List<NoticeUser> noticeUserTypeList= noticeUserMap
                    .get(noticeListDto.getId());
                if(CollUtil.isNotEmpty(noticeUserTypeList)){
                    Map<NoticeUserType, List<String>> userNameTypeMap = noticeUserTypeList.parallelStream()
                        .collect(Collectors.groupingBy(NoticeUser::getType, Collectors
                            .mapping(noticeUser -> userNameMap.get(noticeUser.getUserId()),
                                Collectors.toList())));
                    Map<NoticeUserType, List<Long>> userIdTypeMap = noticeUserTypeList.parallelStream()
                        .collect(Collectors.groupingBy(NoticeUser::getType, Collectors
                            .mapping(NoticeUser::getUserId,
                                Collectors.toList())));
                    noticeListDto.setDurationUserIds(userIdTypeMap.get(NoticeUserType.U));
                    noticeListDto.setDurationUser(userNameTypeMap.get(NoticeUserType.U));

                    noticeListDto.setNoticeUserIds(userIdTypeMap.get(NoticeUserType.T));
                    noticeListDto.setNoticeUser(userNameTypeMap.get(NoticeUserType.T));

                    noticeListDto.setTellUserIds(userIdTypeMap.get(NoticeUserType.D));
                    noticeListDto.setTellUser(userNameTypeMap.get(NoticeUserType.D));

                    noticeListDto.setDateUserIds(userIdTypeMap.get(NoticeUserType.M));
                    noticeListDto.setDateUser(userNameTypeMap.get(NoticeUserType.M));
                }

                List<NoticeSystem> systemTypeList = systemNameListMap
                    .get(noticeListDto.getId());
                if(CollUtil.isNotEmpty(systemTypeList)){
                    Map<SystemType, List<String>> systemTypeListMap = systemTypeList.parallelStream()
                        .collect(Collectors.groupingBy(NoticeSystem::getType, Collectors
                            .mapping(systemType -> systemNameMap.get(systemType.getSystemId()),
                                Collectors.toList())));
                    Map<SystemType, List<Long>> systemIdListMap = systemTypeList.parallelStream()
                        .collect(Collectors.groupingBy(NoticeSystem::getType, Collectors
                            .mapping(NoticeSystem::getSystemId,
                                Collectors.toList())));
                    noticeListDto.setSystemIds(systemIdListMap.get(SystemType.G));
                    noticeListDto.setSystemNames(systemTypeListMap.get(SystemType.G));
                    noticeListDto.setInfluenceIds(systemIdListMap.get(SystemType.S));
                    noticeListDto.setInfluenceNames(systemTypeListMap.get(SystemType.S));
                }

                noticeListDto.setGroupName(groupNameMap.get(noticeListDto.getGroupId()));
                noticeListDto.setTemplateName(templateNameMap.get(noticeListDto.getTemplateId()));
            });
        }
    }

}
